package gocv_utils

import (
	"fmt"
	"gocv.io/x/gocv"
	"image"
	"image/png"
	"os"
)

func LoadImage(imagePath string) (*gocv.Mat, error) {
	img := gocv.IMRead(imagePath, gocv.IMReadColor)
	if img.Empty() {
		return nil, fmt.Errorf("error loading image")
	}
	defer img.Close()
	return &img, nil
}

type matchTemplateResponse struct {
	MinVal     float32
	MaxVal     float32
	MinLoc     image.Point
	MaxLoc     image.Point
	ImgMatRows int
	ImgMatCols int
}

func GetMatchTemplate(img, template string) (*matchTemplateResponse, error) {
	imgMat := gocv.IMRead(img, gocv.IMReadColor)
	if imgMat.Empty() {
		return nil, fmt.Errorf("error loading image1")
	}
	defer imgMat.Close()
	templateMat := gocv.IMRead(template, gocv.IMReadColor)
	if templateMat.Empty() {
		return nil, fmt.Errorf("error loading image2")
	}
	defer templateMat.Close()
	result := gocv.NewMat()
	defer result.Close()
	mask := gocv.NewMat()
	defer mask.Close()
	gocv.MatchTemplate(imgMat, templateMat, &result, gocv.TmCcoeffNormed, mask)
	minVal, maxVal, minLoc, maxLoc := gocv.MinMaxLoc(result)
	fmt.Println(minVal, maxVal, minLoc, maxLoc)
	return &matchTemplateResponse{
		MinVal:     minVal,
		MaxVal:     maxVal,
		MinLoc:     minLoc,
		MaxLoc:     maxLoc,
		ImgMatCols: imgMat.Cols(),
		ImgMatRows: imgMat.Rows(),
	}, nil
}

func MatchTemplate(img, template string, similarPer float32) (bool, error) {
	val, err := GetMatchTemplate(img, template)
	if err != nil {
		return false, err
	}
	return val.MaxVal > similarPer, nil
}

func MatchTemplateToPoint(img, template string, similarPer float32) ([]image.Point, error) {
	val, err := GetMatchTemplate(img, template)
	if err != nil {
		return nil, err
	}
	if val.MaxVal < similarPer {
		return nil, fmt.Errorf("no find image")
	}
	points := []image.Point{
		val.MaxLoc,
		{
			val.ImgMatCols + val.MaxLoc.X,
			val.ImgMatRows + val.MaxLoc.Y,
		},
	}
	return points, nil
}

func MatchTemplateOutPng(img, template string, similarPer float32, fileName string) error {
	imgMat := gocv.IMRead(img, gocv.IMReadColor)
	if imgMat.Empty() {
		return fmt.Errorf("error loading image")
	}
	defer imgMat.Close()
	templateMat := gocv.IMRead(template, gocv.IMReadColor)
	if templateMat.Empty() {
		return fmt.Errorf("error loading image")
	}
	defer templateMat.Close()
	result := gocv.NewMat()
	mask := gocv.NewMat()
	gocv.MatchTemplate(imgMat, templateMat, &result, gocv.TmCcoeffNormed, mask)
	mask.Close()
	minVal, maxVal, minLoc, maxLoc := gocv.MinMaxLoc(result)
	fmt.Println(minVal, maxVal, minLoc, maxLoc)
	if maxVal < similarPer {
		return fmt.Errorf("similarPer")
	}
	subWidth := imgMat.Cols() + maxLoc.X
	subHeight := imgMat.Rows() + maxLoc.Y
	tepImage, _ := templateMat.ToImage()
	rgbImage, _ := tepImage.(*image.RGBA)
	subImage := rgbImage.SubImage(image.Rect(maxLoc.X, maxLoc.Y, subWidth, subHeight)).(*image.RGBA)
	out, _ := os.Create(fileName)
	return png.Encode(out, subImage)
}

func OcrImage(imagePath, newImagePath string) {
	img := gocv.IMRead(imagePath, gocv.IMReadColor)
	if img.Empty() {
		fmt.Println("Error: Could not read image.")
		return
	}
	defer img.Close()
	gocv.CvtColor(img, &img, gocv.ColorBGRToGray)
	gocv.Threshold(img, &img, 0, 255, gocv.ThresholdBinaryInv+gocv.ThresholdOtsu)
	gocv.IMWrite(newImagePath, img)
	return
}
